package registration;

import java.sql.*;
import java.util.*;

import msg.*;

import common.Pair;
import common.dal.*;
import common.dal.SQLDataColumn.Constraints;
import common.exceptions.*;
import common.interfaces.IConsensusManager;

class DBConsensusManager extends AbstractDAL<Consensus, Long> implements IConsensusManager {
	
	protected DBConsensusManager(Transaction t) {
		super(t);
	}
	
	private final static String	CON_ID		= "conId";
	private final static String	EVENT_ID	= "eventId";
	private final static String	NAME		= "name";
	
	static final String			TABLE_NAME	= "consensuses";
	static final String			PRIMARY_KEY	= CON_ID;
	
	@Override
	protected SQLDataColumn[] getTableColumns() {
		return new SQLDataColumn[] {
				new SQLDataColumn(CON_ID, SQLDataType.BIGINT, Constraints.PRIMARY_KEY),
				new SQLDataColumn(EVENT_ID, SQLDataType.BIGINT,
						EnumSet.of(Constraints.FOREIGN_KEY, Constraints.NOT_NULL, Constraints.INDEX),
						Pair.of(DBMessagePersistencyManager.TABLE_NAME, DBMessagePersistencyManager.PRIMARY_KEY)),
				new SQLDataColumn(NAME, SQLDataType.TINYTEXT, Constraints.NOT_NULL)};
	}
	
	@Override
	protected String getTableName() {
		return TABLE_NAME;
	}
	
	@Override
	public void persist(Consensus con) throws InvalidEventException, SQLException {
		if (con == null) {
			throw new IllegalArgumentException("con is null");
		}
		if (exists(con.getId())) {
			throw new ExistingEntityException(con.getId());
		}
		
		try {
			insertInto(new Object[] {con.getId(), con.getEvent().getId(), con.getName()});
		} catch (SQLIntegrityConstraintViolationException e) {
			throw new InvalidEventException(con.getEvent());
		}
	}
	
	@Override
	protected String getPrimaryColumnName() {
		return CON_ID;
	}
	
	@Override
	protected Consensus generateFromResultSet(ResultSet result) throws SQLException {
		long id = result.getLong(CON_ID);
		long eventId = result.getLong(EVENT_ID);
		EventMessage event;
		try {
			event = (EventMessage)MessageManager.getNewInstance(t).get(eventId);
		} catch (InvalidKeyException e) {
			// foreign key constraint forbids this
			throw new AssertionError(e);
		}
		String name = result.getString(NAME);
		return new Consensus(id, name, event);
	}
	
	@Override
	public Collection<Consensus> getAllEventConsensuses(EventMessage event) throws InvalidEventException,
			SQLException {
		if (event == null) {
			throw new IllegalArgumentException("event is null");
		}
		try {
			Message msg = MessageManager.getNewInstance(t).get(event.getId());
			if ((msg instanceof EventMessage) == false) {
				throw new InvalidKeyException(event.getId());
			}
		} catch (InvalidKeyException e) {
			throw new InvalidEventException(event);
		}
		
		try (ResultSet result = selectWhere(new WhereEntry(EVENT_ID, WhereOperator.EQUALS, event.getId()))) {
			Collection<Consensus> $ = new LinkedList<>();
			while (result.next()) {
				$.add(generateFromResultSet(result));
			}
			
			return $;
		}
	}
	
	@Override
	public long getLastId() throws SQLException {
		try (ResultSet set = max(getPrimaryColumnName())) {
			boolean result = set.first();
			assert result;
			return set.getLong(1);
		}
	}
	
	public void removeAllConsensuses(EventMessage event) throws SQLException {
		deleteWhere(new WhereEntry(EVENT_ID, WhereOperator.EQUALS, event.getId()));
	}
}
